﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Fiddler;
using System.Collections;
using CSharp.Libs.Koc.KernelModels;
using CSharp.Libs.Misc;
using System.IO;

namespace CSharp.Libs.Koc
{
    public class SeedCollector
    {
        #region declarations
        // Main kernel
        private Kernel _KRNL = null;

        // MainSrc and Seed specific
        private bool _fSaveSeed2Disk = false;
        private Int32 _intSeedCount = 0;
        private String _strMainSrcSeedStart = "";
        private String _strMainSrcSeedEnd = "";
        private Dictionary<string, object> _dicSeeds = new Dictionary<string, object>();
        private const String KEY_SEED_EXTENSION_FULL_URL = "FullUrl";
        private const String KEY_SEED_EXTENSION_SEED_COUNTER = "SeedCounter";

        #region events
        public delegate void SeedReceivedEventHandler(object sender, SeedReceivedEventArgs srea);
        public event SeedReceivedEventHandler SeedReceived;
        private void ThrowSeedReceivedEvent(
            SeedReceivedEventArgs srea)
        {
            if (SeedReceived != null)
            {
                SeedReceived(this, srea);
            }
        }
        #endregion
        #endregion



        #region constructor / terminator
        public SeedCollector(
            Kernel KRNL)
        {
            _KRNL = KRNL;

            //Get options
            _strMainSrcSeedStart = _KRNL.LAO.GetOption(constants.LAO_SEEK_STRING_MAIN_SRC_SEED_START);
            _strMainSrcSeedEnd = _KRNL.LAO.GetOption(constants.LAO_SEEK_STRING_MAIN_SRC_SEED_END);
        }
        #endregion



        #region event handling
        #endregion



        #region private functions
        #region seed receiving
        /// <summary>_GetSeed
        ///     retreives the seed variable off the Main_Src page.
        /// </summary>
        /// <history>21.03.2011 created</history>
        /// <history>25.07.2011 adapted from old TrafficMonitor using HttpMonitor.dll COM class</history>
        /// <history>14.10.2011 added handling of multiple servers</history>
        private void _ReceiveMainSeed(
            Session oSession)
        {
            try
            {
                if (oSession.fullUrl.ToLower().Contains(string.Concat(PhpCommands.main_src.ToString(), ".php")))
                {
                    String strMainPage = oSession.GetResponseBodyAsString();

                    //Check if Mainpage contains start and end at all
                    if (strMainPage.Contains(_strMainSrcSeedStart) &&
                        strMainPage.Contains(_strMainSrcSeedEnd))
                    {
                        //get starting index of seed variabe in page's source
                        Int32 intStart = strMainPage.IndexOf(_strMainSrcSeedStart) + _strMainSrcSeedStart.Length + 1;

                        if (intStart > 0)
                        {
                            //get ending index of seed variable in page's source
                            Int32 intEnd = strMainPage.IndexOf(_strMainSrcSeedEnd, intStart + 1);

                            if (intEnd > intStart)
                            {
                                //get seed variable's string
                                String strSeed = strMainPage.Substring(intStart, intEnd - intStart);

                                if (strSeed != "")
                                {
                                    //get Hashtable of Seed
                                    Hashtable htSeed = JSON.JsonDecode(strSeed) as Hashtable;

                                    if (htSeed != null)
                                    {
                                        //get Facebook user id of seed
                                        string strFbUid = _GetFbUserIdOfSeed(strMainPage);//important: get it out of mainpage

                                        //get ServerId
                                        int intServerId = _GetServerIdOfSeed(oSession.fullUrl);

                                        //create key
                                        string strKey = _GetKey(strFbUid, intServerId.ToString());

                                        //Save seed 2 disk?
                                        if (_fSaveSeed2Disk)
                                        {
                                            _saveSeedToDisk(strKey, strSeed);
                                        }

                                        //init counter
                                        int intLastCount = 0;

                                        //Add seed to dictionary
                                        if (_dicSeeds.ContainsKey(strKey))
                                        {
                                            //full URL and counter refresh
                                            intLastCount = (int)((Hashtable)_dicSeeds[strKey])[KEY_SEED_EXTENSION_SEED_COUNTER];
                                        }
                                        else
                                        {
                                            _dicSeeds.Add(strKey, null);
                                        }

                                        //add extensions to seed
                                        htSeed.Add(KEY_SEED_EXTENSION_FULL_URL, oSession.fullUrl);
                                        htSeed.Add(KEY_SEED_EXTENSION_SEED_COUNTER, intLastCount + 1);

                                        //set seed
                                        _dicSeeds[strKey] = htSeed;
                                        
                                        //test to recreate seed string
                                        strSeed = JSON.JsonEncode(htSeed);

                                        //increment seed counter and throw seed event
                                        _intSeedCount++;
                                        ThrowSeedReceivedEvent(new SeedReceivedEventArgs(intServerId, htSeed, strSeed, strKey, strFbUid));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _KRNL.EC.AddException(ex, this.ToString(), _KRNL.EC.Tools.GetCurrentMethodName());
            }
        }

        /// <summary>_GetServerIdOfSeed</summary>
        /// <param name="FullUrl"></param>
        /// <returns></returns>
        /// <history>created  14.10.2011</history>
        private int _GetServerIdOfSeed(
            String FullUrl)
        {
            int intServerId = 0;

            //get number of s parameter (preferred way)
            String[] strUrlSplit = FullUrl.Split('?');

            if (strUrlSplit.Count() == 2 &&
                strUrlSplit[1] != "")
            {
                Dictionary<String, String> dicNewParams = _KRNL.UH.GetParameterDictionary(strUrlSplit[1]);

                if (dicNewParams != null &&
                    dicNewParams.Count > 0)
                {
                    if (dicNewParams.ContainsKey("s"))
                    {
                        if (!int.TryParse(dicNewParams["s"], out intServerId))
                        {
                            intServerId = -1;
                        }
                    }
                }
            }

            //get number after www only if no number
            if (intServerId <= 0)
            {
                //not yet implemented
                throw new NotImplementedException();
            }

            return intServerId;
        }

        /// <summary>_GetFbUserIdOfSeed</summary>
        /// <param name="strMainPage"></param>
        /// <returns></returns>
        /// <history>created  27.01.2012</history>
        private string _GetFbUserIdOfSeed(
            string strMainPage)
        {
            //get starting index of uid
            Int32 intStart = strMainPage.IndexOf("user_id = '") + "user_id = '".Length;

            if (intStart > 0)
            {
                //get ending index of seed variable in page's source
                Int32 intEnd = strMainPage.IndexOf("';", intStart);

                if (intEnd > intStart)
                {
                    //get seed variable's string
                    string strTest = strMainPage.Substring(intStart, intEnd - intStart);
                    return strMainPage.Substring(intStart, intEnd - intStart);
                }
            }

            return "";
        }

        /// <summary>_GetKey</summary>
        /// <param name="FbUid"></param>
        /// <param name="ServerId"></param>
        /// <returns></returns>
        /// <history>created  13.02.2012</history>
        private string _GetKey(
            string FbUid,
            string ServerId)
        {
            return string.Concat(FbUid, "_", ServerId);
        }

        /// <summary>_saveSeedToDisk</summary>
        /// <param name="Filename"></param>
        /// <param name="strSeed"></param>
        /// <history>30.01.2012</history>
        private void _saveSeedToDisk(
            string Filename,
            string strSeed)
        {
            DateTime datNow = DateTime.Now;
            string strTimestamp = string.Concat(
                datNow.Year.ToString("0000"),
                datNow.Month.ToString("00"),
                datNow.Day.ToString("00"),
                datNow.Hour.ToString("00"),
                datNow.Minute.ToString("00"),
                datNow.Second.ToString("00"));
            Filename = string.Concat(Filename, "_", strTimestamp, ".json");
            using (StreamWriter file = new StreamWriter(@Filename))
            {
                file.Write(strSeed);
                file.Flush();
                file.Close();
            }
        }
        #endregion

        /// <summary>_GetSeedByKey</summary>
        /// <param name="Key"></param>
        /// <returns></returns>
        /// <history>created  28.01.2012</history>
        private object _GetSeedByKey(
            string Key)
        {
            if (_dicSeeds.ContainsKey(Key))
            {
                return _dicSeeds[Key];
            }

            return null;
        }
        #endregion



        #region interface
        #region properties
        #region seed
        /// <summary>Seeds dictionary
        ///  - contains the current received seeds of every user and every server visited</summary>
        /// <remarks></remarks>
        /// <history>created  14.10.2011 new seed dictionary</history>
        /// <history>modified 28.01.2012 moved to SeedCollector class</history>
        public Dictionary<string, object> Seeds
        {
            get
            {
                return _dicSeeds;
            }
        }

        public bool SaveSeedToDisk
        {
            get
            {
                return _fSaveSeed2Disk;
            }
            set
            {
                _fSaveSeed2Disk = value;
            }
        }
        #endregion
        #endregion

        #region methods
        /// <summary>AnalyzeSeedSession</summary>
        /// <param name="oSession"></param>
        /// <history>created  28.01.2012</history>
        public void AnalyzeSeedSession(
            Session oSession)
        {
            _ReceiveMainSeed(oSession);
        }

        /// <summary>GetSeedByKey</summary>
        /// <param name="Key"></param>
        /// <returns></returns>
        /// <history>created  28.01.2012</history>
        public object GetSeedByKey(
            string Key)
        {
            return _GetSeedByKey(Key);
        }

        /// <summary>GetKey</summary>
        /// <param name="FbUid"></param>
        /// <param name="ServerId"></param>
        /// <returns></returns>
        /// <history>created  13.02.2012</history>
        public string GetKey(
            string FbUid,
            string ServerId)
        {
            return _GetKey(FbUid, ServerId);
        }
        #endregion
        #endregion
    }
}
